﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using SilverPOP.Data.Process.Entity;
using SilverPOP.Data.Process.BLL;
using Helpers;
using Utilities;
using Atp.Net;
using SilverPOP.Library.BusinessEntities;
using System.Xml;
using System.Threading;
using System.Dynamic;
using System.Data;
using SilverPOP.Data.Process.Helpers.XmlConverter;

namespace SilverPOP.Data.Process.OperationUnit
{
    public class DataSyncProcess : DataAndSchemaProcess
    {
        #region Fields
        private long _totalNonResponder = 0;
        #endregion

        #region Constructor
        //public DataSyncProcess(long campaignId)
        //{
        //    this.campaignId = campaignId;
        //    this.CreateFolder(ConfigHelpers.LocalUploadDirectoryName);
        //}


        List<DatabaseSchemaEntity> _databaseSchemaEntity = null;

        public DataSyncProcess(TaskListEntity task)
        {

                      _databaseSchemaEntity = BLL.DatabaseSchema.GetDatabaseSchemaByProjectId(task.ProjectId);

                       DAL.DAL.SetConnectionString(task.ServerName, task.DatabaseName, task.Username, task.Password);               
                       this.CreateFolder(ConfigHelpers.LocalUploadDirectoryName + @"\" +task.ProjectName);
                       this.campaignId = task.CampaignId;                                
        }
        #endregion


        public override void ExecuteOperation()
        {
            //try
            //{
                this.processStartingTime = DateTime.Now.TimeOfDay;
                Console.WriteLine("Non Responders data sync process started.");

                List<ContactListCreationEntity> contactEntityCreationList = ContactListCreationProcess();
             
                if (contactEntityCreationList != null && contactEntityCreationList.Count > 0)
                {
                        NonRespondersDataExportInSilverPOP(contactEntityCreationList);
                }
                

                Console.WriteLine("Non Responders data sync process completed.");
                Console.WriteLine("Total Non Responders: " + _totalNonResponder);

                FileWriter.WriteToFile(this.successFileNameWithPath, "Total Non Responders: " + _totalNonResponder);
                this.CalculateTotalProcessingTime();

            //}
            //catch(Exception ex)
            //{
            //    this.LogError(ex);
            //    throw ex;
            //}
        }

 

        #region Contact List Created In SilverPOP Database

        private bool IsContactListAlreadyCreated(List<ContactListCreationEntity> contactEntityCreationList)
        {
            //=================================================================================
               //For a campaign blast id silver pop contact list must be created only one time.
              //If silver pop contact list already created before then data sync will not continue,
              //because data already synced  when silver pop contact list created
            //==================================================================================
            foreach (ContactListCreationEntity entity in contactEntityCreationList)
            {
                foreach(long blastId in entity.CampaignAndItsBlast.BlastIDs)
                {
                   List<long> contactList = DataSyncBLL.GetActiveContactListByBlastID(blastId);

                   if (contactList != null)
                   {
                       throw new Exception("Contact list already created for blast Id: " + blastId + " and Campaign Id: " + entity.CampaignAndItsBlast.Campaign.CampaignID+" . Data already synced.");
                   }
                }
            }

            return false;
        }

        private  List<ContactListCreationEntity> ContactListCreationProcess()
        {
            Console.WriteLine("Contact List Creation In SilverPOP Started ...");
            FileWriter.WriteToFile(this.successFileNameWithPath, "Contact List Creation In SilverPOP Started ...");
            
            List<ContactListCreationEntity> contactEntityCreationList = DataSyncBLL.PopulateContactEntityCreationObjects(this.campaignId);

            if (contactEntityCreationList != null && contactEntityCreationList.Count > 0)
            {
                //Check contact list already created or not
                if (!IsContactListAlreadyCreated(contactEntityCreationList))
                {
                    foreach (ContactListCreationEntity contactEntity in contactEntityCreationList)
                    {
                        if (contactEntity.Segment != null && !String.IsNullOrEmpty(contactEntity.SilverPOPDatabaseName))
                        {
                            foreach (Segment segment in contactEntity.Segment)
                            {
                                //String dateTimeContactList = DateTime.Now.ToShortDateString().Replace("/", "-") + "-" + DateTime.Now.Hour + "-" + DateTime.Now.Minute + "-" + DateTime.Now.Second;
                                String contactListName = segment.SegmentName + "_" + segment.SegmentCode;
                                long contactListId = CreateContactListInSilverPOP(contactEntity.SilverPOPDatabaseID, contactListName, (int)ListVisibility.Shared);


                                if (contactListId > 0)
                                {
                                    Console.WriteLine("Contact list for campaign{0} is created. Contact List Id:{1}", contactEntity.CampaignAndItsBlast.Campaign.CampaignName, contactListId);
                                    segment.SilverPOPContactListID = contactListId;

                                    if (contactEntity.CampaignAndItsBlast.BlastIDs != null && contactEntity.CampaignAndItsBlast.BlastIDs[0] > 0)
                                    {
                                        DataSyncBLL.UpdateBlasSegmentWithContactListID(contactListId, contactEntity.CampaignAndItsBlast.BlastIDs[0], segment.SegmentId);
                                    }

                                    FileWriter.WriteToFile(this.successFileNameWithPath, "Contact list for campaign: " + contactEntity.CampaignAndItsBlast.Campaign.CampaignName + "  is created. Contact List Id: " + contactListId);
                                }
                            }
                        }

                    }//end foreach

                }//end checking contact list already existed
            }

            Console.WriteLine("Contact List Creation In SilverPOP Completed.");
            return contactEntityCreationList;
        }

        private long CreateContactListInSilverPOP(long databaseId, String contactListName, int visibility)
        {

            SilverPopAccount silverPopAccount = this.InstanceSilverPOPAccount;

            if (silverPopAccount != null)
            {

                return SilverPOP.Library.Helpers.SilverPopHelpers.CreateContactList(silverPopAccount, databaseId, contactListName, visibility);
            }
            else
            {
                throw new Exception("SilverPOP account not found.");
            }
        }

        #endregion



        #region Importing Non Responder Data  In SilverPOP Database
        private void NonRespondersDataExportInSilverPOP(List<ContactListCreationEntity> contactEntityCreationList)
        {
            List<String> uploadingFileNames = new List<string>();

            if (GetNonRespondersAndDoRelatedTask(uploadingFileNames, contactEntityCreationList)) // Get Non responders list from DB and then generate CSV and xml mapper file
            {
                if (UploadFileInSilverPOPFTP(uploadingFileNames)) //Upload generated csv file and xml mapper to SilverPOP FTP Server
                {
                    ImportDataToSilverPOPDatabase(uploadingFileNames); // Import data in SilverPOP Database
                }
            }

        }

        #region Get All Non Responders and Generate CSV Files and Their Related XML Schema Mapper


        private bool GetNonRespondersAndDoRelatedTask(List<String> uploadingFTPFileNames, List<ContactListCreationEntity> contactEntityCreationList)
        {

            foreach (ContactListCreationEntity contactEntity in contactEntityCreationList)
            {

                Console.WriteLine("Non responder's data fetching started from Database for CampaignID: " + contactEntity.CampaignAndItsBlast.Campaign.CampaignID);
                var nonResponderDataTable = DataSyncBLL.GetAllNonResponderDataTable(contactEntity.CampaignAndItsBlast.Campaign.CampaignID, this.errorFileNameWithPath);      
    
                Console.WriteLine("Non responder's data fetching completed for CampaignID: " + contactEntity.CampaignAndItsBlast.Campaign.CampaignID + " and campaign name: " + contactEntity.CampaignAndItsBlast.Campaign.CampaignName);
                FileWriter.WriteToFile(this.successFileNameWithPath, "Non responder's data fetching completed for CampaignID: " + contactEntity.CampaignAndItsBlast.Campaign.CampaignID + " and campaign name: " + contactEntity.CampaignAndItsBlast.Campaign.CampaignName);


                if (contactEntity.Segment != null && nonResponderDataTable != null && nonResponderDataTable.Rows.Count > 0)
                {
                    _totalNonResponder += nonResponderDataTable.Rows.Count;

                    FileWriter.WriteToFile(this.successFileNameWithPath, "Total non responders for Campaign: " + contactEntity.CampaignAndItsBlast.Campaign.CampaignName + " is: " + nonResponderDataTable.Rows.Count);

                    foreach (Segment segment in contactEntity.Segment)
                    {

                       /// List<NonResponder> filterNonResponderBySegment = nonResponderDataTable.Where(x => x.Segment.ToLower() == segment.SegmentCode.ToLower()).ToList();

                        DataTable filterNonResponderBySegment = nonResponderDataTable.AsEnumerable().Where(x => x.Field<string>("Segment").ToLower() == segment.SegmentCode.ToLower()).CopyToDataTable();                      

                        if (filterNonResponderBySegment != null && filterNonResponderBySegment.Rows.Count > 0)
                        {
                            String fileName = contactEntity.SilverPOPDatabaseID + "-" + segment.SegmentCode + ".csv";
                            uploadingFTPFileNames.Add(fileName);
                            CreateCSVFileAndItsRelatedMapperXMLFile(filterNonResponderBySegment, fileName, contactEntity.SilverPOPDatabaseID, segment);

                            FileWriter.WriteToFile(this.successFileNameWithPath, "Non responders count for Segment: " + segment.SegmentCode + " is: " + filterNonResponderBySegment.Rows.Count);
                        }
                    }
                }




            }

            return true;
        }


        private void CreateCSVFileAndItsRelatedMapperXMLFile(DataTable nonResponderDataTable, String fileName, long databaseId, Segment segment)
        {
            CsvUtility.ExportDataTableToCSVAndSaveInFolder(nonResponderDataTable, ",", this.directoryName, fileName);
            Console.WriteLine("Csv file created. File Name is: " + fileName);

            FileWriter.WriteToFile(this.successFileNameWithPath, "Csv file created. File Name is: " + fileName);

            //CSV file created, now we will create schema definition for this file
           // String schmeaText = File.ReadAllText(ConfigHelpers.SchemaMapperFileWithContactList);

           // String schmeaText = XmlConverterHelpers.GetConvertedXmlFile(_databaseSchemaEntity.Where(x => x.IsWithContactList == true).ToList());
            String schmeaText = XmlConverterHelpers.GetConvertedXmlFile(_databaseSchemaEntity,true);
            schmeaText = schmeaText.Replace("###Action###", ActionType.ADD_AND_UPDATE.ToString());
            schmeaText = schmeaText.Replace("###ListID###", databaseId.ToString());
            schmeaText = schmeaText.Replace("###ListVisibility###", ((int)ListVisibility.Shared).ToString());
            schmeaText = schmeaText.Replace("###FileType###", ((int)FileType.CSV).ToString());


            schmeaText = schmeaText.Replace("###ContactList###", "<CONTACT_LISTS><CONTACT_LIST_ID>" + segment.SilverPOPContactListID + "</CONTACT_LIST_ID></CONTACT_LISTS>");



            String mapperfileName = fileName.Replace(".csv", ".xml");
            String schemaFileNameWithPath = this.directoryName + @"\" + mapperfileName;

            XmlDocument doc = new XmlDocument();
            doc.LoadXml(schmeaText);
            doc.PreserveWhitespace = true;
            doc.Save(schemaFileNameWithPath);

            Console.WriteLine("XML mapper file for CSV: {0}  is created. Mapper File Name is: {1} ", fileName, mapperfileName);
            FileWriter.WriteToFile(this.successFileNameWithPath, "XML mapper file for CSV file: " + fileName + "  is created. Mapper File Name is: " + mapperfileName);
        }



        #endregion


        #region Upload File In SilverPOP FTP
        private  bool UploadFileInSilverPOPFTP(List<String> uploadingFTPFileNames)
        {

            if (uploadingFTPFileNames != null && uploadingFTPFileNames.Count > 0)
            {
                Console.WriteLine("Conecting to FTP...");
                FileWriter.WriteToFile(this.successFileNameWithPath, "Conecting to FTP...");

                String remoteLocation = String.Empty;
                String localLocation = this.directoryName;

                Sftp client = new Sftp();
                client.Connect(ConfigHelpers.FTPHost, ConfigHelpers.FTPPort);
                client.Authenticate(ConfigHelpers.FTPUserName, ConfigHelpers.FTPPassword);


                if (client.IsConnected)
                {
                    Console.WriteLine("Successfully connected to FTP.");
                    FileWriter.WriteToFile(this.successFileNameWithPath, "Successfully connected to FTP.");

                    client.KeepAlive();
                    String defaultDir = client.GetCurrentDirectory();
                    defaultDir += ConfigHelpers.FTPUploadDirectoryName;

                    Console.WriteLine("File uploading is going to start...");

                    foreach (String uploadingFileName in uploadingFTPFileNames)
                    {
                        String xmlMapperFileName = uploadingFileName.Replace(".csv", ".xml");


                        //local file name with path csv file and xml mapper
                        String localCSVFileNameWithPath = localLocation + @"\" + uploadingFileName;
                        String localXMLMapperFileNameWithPath = localLocation + @"\" + xmlMapperFileName;


                        //remote file name with path csv file and xml mapper
                        String remoteCSVFileNameWithPath = defaultDir + @"/" + uploadingFileName;
                        String remoteXMLMapperFileNameWithPath = defaultDir + @"/" + xmlMapperFileName;

                        if (File.Exists(localCSVFileNameWithPath))
                        {
                            Console.WriteLine("File uploading is going on ...");

                            long identifier = client.UploadFile(localCSVFileNameWithPath, remoteCSVFileNameWithPath);
                            long identifier2 = client.UploadFile(localXMLMapperFileNameWithPath, remoteXMLMapperFileNameWithPath);


                            Thread.Sleep(ConfigHelpers.WaitingTimePerFile);


                            Console.WriteLine("CSV File uploaded successfully. File name is: " + uploadingFileName);
                            Console.WriteLine("XML Mapper File uploaded successfully. File name is: " + xmlMapperFileName);

                            FileWriter.WriteToFile(this.successFileNameWithPath, "CSV File uploaded successfully. File name is: " + uploadingFileName);
                            FileWriter.WriteToFile(this.successFileNameWithPath, "XML Mapper File uploaded successfully. File name is: " + xmlMapperFileName);

                        }


                    }

                    client.KeepAlive();

                }

                //wait for one minute
                Console.WriteLine("Wait uploading is going on ...");
                Thread.Sleep(ConfigHelpers.OverAllWaitingTime);
                Console.WriteLine("File uploading completed.");
                return true;
            }
            else
            {
                Console.WriteLine("There is no file for uploading...");
                FileWriter.WriteToFile(this.errorFileNameWithPath, "There is no file for uploading.");
                return false;
            }

        }

        #endregion

        #region Import Data In SilverPOP Database
        private  void ImportDataToSilverPOPDatabase(List<String> uploadingFTPFileNames)
        {
            Console.WriteLine("Data sync is going to start in SilverPOP Database ...");
            SilverPopAccount silverPopAccount = this.InstanceSilverPOPAccount;

            if (silverPopAccount != null)
            {
                Console.WriteLine("Data sync is started ...");
                FileWriter.WriteToFile(this.successFileNameWithPath, "Data sync is started in SilverPOP Database.");
                Dictionary<String, String> importResult = SilverPOP.Library.Helpers.SilverPopHelpers.ImportDataToSilverPOPDatabase(silverPopAccount, uploadingFTPFileNames);

                if (importResult != null && importResult.Count > 0)
                {
                    foreach (KeyValuePair<String, String> keyValue in importResult)
                    {
                        if (keyValue.Key == "Error")
                        {
                            Console.WriteLine(keyValue.Value);
                            FileWriter.WriteToFile(this.errorFileNameWithPath, "Error during importing data in SilverPOP: " + keyValue.Value);
                        }
                        else
                        {
                            String[] keyValueArray = keyValue.Value.Split('-');
                            if (keyValueArray.Length < 2)
                            {
                                Console.WriteLine("File name: " + keyValue.Key + " :" + keyValue.Value);
                                FileWriter.WriteToFile(this.successFileNameWithPath, "File name: " + keyValue.Key + " :" + keyValue.Value);
                            }
                            else if (keyValueArray.Length == 2)
                            {
                                Console.WriteLine("File name: " + keyValue.Key + " :" + keyValueArray[0] + "  and Job ID: " + keyValueArray[1]);
                                FileWriter.WriteToFile(this.successFileNameWithPath, "File name: " + keyValue.Key + " :" + keyValueArray[0] + "  and Job ID: " + keyValueArray[1]);
                            }
                        }
                    }
                }
            }
            else
            {
                throw new Exception("SilverPOP account not found.");
            }

            Console.WriteLine("Data sync in SilverPOP Database has completed.");
        }
        #endregion

        #endregion
    
    }//end class
}
